﻿#include "OiPCH.hpp"
#include "OiPlyTool.hpp"


namespace Oi
{
    namespace PLScannerCore
    {
        class PlyToolImpl : public Impl<PlyTool>
        {
        public:
            void moveToZero(OiProfile& profile, bool dir, int method);

            void arrangeProfile(OiProfile& profile);

            void mapDefinition(const std::vector<cv::Point2f> src, const std::vector<std::pair<int, cv::Point2f>> dst, const std::vector<cv::Point2f> full, std::vector<std::pair<int, cv::Point2f>>& mapPoints,  double& offset);
        };

        void PlyToolImpl::moveToZero(OiProfile& profile, bool dir, int method)
        {
            if (method == 0)
            {
                double centreX = std::accumulate(std::begin(profile), std::end(profile), double(0.0), [](double v, const QPointF & p) { return p.x() + v; }) / profile.size();

                if (dir)
                {
                    for (auto& p : profile)
                    {
                        p.setX(p.x() - centreX + PLScanner::instance()->measureOffsetX1);
                    }
                }
                else
                {
                    for (auto& p : profile)
                    {
                        p.setX(p.x() - centreX + PLScanner::instance()->measureOffsetX2);
                    }
                }
            }
            else if (method == 1)
            {
                double minError = 99999.0;

                double minIndex = 0;

                for (int i = profile.size() / 2 - 10; i < profile.size() / 2 + 10; i++)
                {
                    double  diff = 0.0;
                    int count = 0;
                    double cp = profile[i].x();

                    int bx = profile.size() - 1;
                    for (int j = 0; j <  qMin(i, profile.size() - i); j++)
                    {
                        auto jy = profile[j].x();
                        auto by = profile[bx].x();

                        if ((cp - jy) - (by - cp) > 0.01)
                        {
                            continue;
                        }
                        
                        while ((cp - jy) - (by - cp) < -0.01)
                        {
                            bx--;
                            if (bx >= 0 )
                            {
                                by = profile[bx].x();
                            }
                            else
                            {
                                break;
                            }
                            
                        }

                        if (fabs(cp - jy - by + cp) <= 0.01)
                        {
                            diff += fabs(profile[bx].y() - profile[j].y());
                            count++;
                        }
                    }

                    if (count > 0)
                    {
                        diff /= count;

                        if (diff < minError)
                        {
                            minError = diff;
                            minIndex = i;
                        }
                    }
                }


                double centreX = 0.0;

                if (minIndex > 0)
                {
                    centreX = profile[minIndex].x();
                }
                else
                {
                    centreX = std::accumulate(std::begin(profile), std::end(profile), double(0.0), [](double v, const QPointF & p) { return p.x() + v; }) / profile.size();
                }

                for (auto& p : profile)
                {
                    p.setX(p.x() - centreX);
                }
            }
            
        }

        void PlyToolImpl::arrangeProfile(OiProfile& profile)
        {
            OiProfiles ps;
            OiProfile tempList;

            for (int i = 0; i < profile.size(); i++)
            {
                if (profile[i].y() <= 40.0 && profile[i].y() > 0.0)
                {
                    tempList.append(profile[i]);
                }
                else
                {
                    if (tempList.isEmpty())
                    {
                        continue;
                    }
                    else
                    {
                        QPointF pre = tempList.last();
                        int nextIndex = i;

                        for (; nextIndex < profile.size(); nextIndex++)
                        {
                            if (profile[nextIndex].y() <= 40.0 && profile[nextIndex].y() >0.0)
                            {
                                break;
                            }
                        }

                        if (nextIndex <= profile.size() - 1)
                        {
                            QPointF next = profile[nextIndex];

                            if ((next.x() - pre.x()) > 2.0)
                            {
                                ps << tempList;
                                tempList.clear();
                                i = nextIndex;
                            }
                            else
                            {
                                double l1 = fabs(profile[i].x() - pre.x());
                                double l2 = fabs(profile[i].x() - next.x());

                                tempList.append(QPointF(profile[i].x(), (pre.y() * l2 + next.y() * l1) / (l1 + l2)));
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }

            ps << tempList;

            std::sort(std::begin(ps), std::end(ps), [](OiProfile& l1, OiProfile& l2) {return l1.size() > l2.size(); });
            if (ps.size() > 0)
            {
                profile = ps.front();
            }

        }

        void PlyToolImpl::mapDefinition(const std::vector<cv::Point2f> src, const std::vector<std::pair<int, cv::Point2f>> dst, const std::vector<cv::Point2f> full, std::vector<std::pair<int, cv::Point2f>>& mapPoints, double& offset)
        {
            offset = 0.0;

            double offset2 = 0.0;

            double error1 = 0.0, error2 = +99999.0;
            std::vector<cv::Point2f> src1 = src;
            std::vector<cv::Point2f> full1 = full;

            while (1)
            {
                error1 = 0.0;

                double offset1 = 0.0;

                std::vector<std::pair<int, cv::Point2f>> mapPoints1;

                float srcSearch = -9999.0;

                for (int di = 0; di < dst.size(); di++)
                {
                    double dst_v1 = 0.0, dst_v2 = 0.0;
                    if (di == 0)
                    {
                        dst_v1 = M_PI / 2;
                        dst_v2 = atan2(dst[di].second.y - dst[di + 1].second.y, dst[di].second.x - dst[di + 1].second.x);
                    }
                    else if (di == dst.size() - 1)
                    {
                        dst_v1 = atan2(dst[di].second.y - dst[di - 1].second.y, dst[di].second.x - dst[di - 1].second.x);
                        dst_v2 = M_PI / 2;
                    }
                    else
                    {
                        dst_v1 = atan2(dst[di].second.y - dst[di - 1].second.y, dst[di].second.x - dst[di - 1].second.x);
                        dst_v2 = atan2(dst[di].second.y - dst[di + 1].second.y, dst[di].second.x - dst[di + 1].second.x);
                    }

                    double cornerindex = 0;
                    double cornerValue = 1.0;

                    cv::Point2d preSrc, nextSrc;

                    for (int i = 0; i < src1.size() - 1; i++)
                    {
                        if (src1[i].x <= srcSearch)
                        {
                            continue;
                        }
                        if (i == 0)
                        {
                            preSrc = src1.front();
                            nextSrc = src1[i + 1];
                        }
                        else if (i == dst.size() - 1)
                        {
                            preSrc = src1[i - 1];
                            nextSrc = src1.back();
                        }
                        else
                        {
                            preSrc = src1[i - 1];
                            nextSrc = src1[i + 1];
                        }
                        double src_v1 = atan2(src1[i].y - preSrc.y, src1[i].x - preSrc.x);
                        double src_v2 = atan2(src1[i].y - nextSrc.y, src1[i].x - nextSrc.x);
                        double diff = fabs(src_v1 - dst_v1) + fabs(src_v2 - dst_v2);

                        if (src1[i].x - dst[di].second.x > 10.0)
                        {
                            break;
                        }

                        if (diff < cornerValue)
                        {
                            cornerValue = diff;
                            cornerindex = i;
                        }
                    }

                    if (cornerValue >= 0.1)
                    {
                        double disIndex = 0;
                        double disValue = 10.0;
                        for (int i = 0; i < full1.size() - 1; i++)
                        {
                            if (full1[i].x <= srcSearch)
                            {
                                continue;
                            }
                            if (full1[i].x - dst[di].second.x > 10.0)
                            {
                                break;
                            }

                            double diff = sqrt(pow(full1[i].x - dst[di].second.x, 2) + pow(full1[i].y - dst[di].second.y, 2));
                            if (diff < disValue)
                            {
                                disValue = diff;
                                disIndex = i;
                            }
                        }

                        if (disValue >= 10.0)
                        {
                            mapPoints1.push_back(std::pair<int, cv::Point2f>(dst[di].first, cv::Point2f(dst[0].second.x, std::nan(""))));

                            error1 += 10000;

                            offset1 += 0.0;
                        }
                        else
                        {
                            mapPoints1.push_back(std::pair<int, cv::Point2f>(dst[di].first, full1[disIndex]));
                            srcSearch = full1[disIndex].x;

                            error1 += disIndex;

                            offset1 += (dst[di].second.x - full1[disIndex].x);
                        }
                    }
                    else
                    {
                        mapPoints1.push_back(std::pair<int, cv::Point2f>(dst[di].first, src1[cornerindex]));
                        srcSearch = src1[cornerindex].x;

                        error1 += cornerValue;

                        offset1 += (dst[di].second.x - src1[cornerindex].x);
                    }
                }

                error1 /= dst.size();

                if (error1 < error2)
                {
                    error2 = error1;
                }
                else
                {
                    offset = offset2;

                    break;
                }

                mapPoints = mapPoints1;


                if (fabs(offset1 - offset) < 0.05)
                {
                    break;
                }

                if (fabs(offset) < 0.05)
                {
                    break;
                }

                offset2 = offset;

                offset = offset1;

                for (auto& v : src1)
                {
                    v.x += offset;
                }

                for (auto& v : full1)
                {
                    v.x += offset;
                }
            }
        }

        PlyTool::PlyTool(QObject *parent /*= 0*/)
            : QObject(parent)
        {
            OI_I(PlyTool);
        }

        void PlyTool::calResult(WorkResult::Result& r, bool dir)
        {
            OI_F(PlyTool);

            if (r.profile.size() < 20)
            {
                r.result = WorkResult::RC_ProfileEmpty;
                return;
            }

            r.data.clear();

            d->arrangeProfile(r.profile);

            
            d->moveToZero(r.profile, dir, PLScanner::instance()->zeroMethod);

            std::vector<std::pair<int, cv::Point2f>> dstPointsPair;

            dstPointsPair.push_back(std::pair<int, cv::Point2f> (TT_LeftSide, cv::Point2f(-r.params.materialsWidth / 2, r.params.materialsThickness)));
            dstPointsPair.push_back(std::pair<int, cv::Point2f> (TT_RightSide, cv::Point2f(+r.params.materialsWidth / 2, r.params.materialsThickness)));

            int i = 0;
            for (auto dp : r.params.definitionPoints)
            {
                dstPointsPair.push_back(std::pair<int, cv::Point2f>(i, cv::Point2f(dp.distance, dp.thicknessLeft)));
                i++;
            }
            
            std::sort(std::begin(dstPointsPair), std::end(dstPointsPair), [](auto & v1, auto & v2) {return  v1.second.x < v2.second.x; });

            std::vector<cv::Point2f> contour, poly;

            for (auto p : r.profile)
            {
                contour.push_back(cv::Point2d(p.x(), p.y()));
            }

            cv::approxPolyDP(contour, poly, 0.1, false);
            poly.insert(poly.begin(), cv::Point2d(r.profile.front().x(), 0.0));
            poly.push_back(cv::Point2f(r.profile.last().x(), 0.0));
            QList<QPointF> measureThickness;

            if (r.params.measureThickness.size() > 0)
            {
                QList<std::pair<int, QPointF>> mtp;

                for (int i = 0; i < r.params.measureThickness.size(); i++)
                {
                    mtp.append(std::pair<int, QPointF>(i, r.params.measureThickness[i]));
                    measureThickness.append(QPointF(r.params.measureThickness[i].x(), 0.0));
                }

                std::sort(std::begin(mtp), std::end(mtp), [](const auto v1, const auto v2) {return v1.second.x() < v2.second.x(); });

                int closeIndex = 0;

                for (auto t : mtp)
                {
                    int index = t.first;
                    QPointF ip = t.second;

                    while (r.profile[closeIndex].x() > ip.x())
                    {
                        closeIndex--;

                        if (closeIndex <= 0)
                        {
                            closeIndex = 0;
                            break;
                        }
                    }

                    while (r.profile[closeIndex + 1].x() < ip.x())
                    {
                        closeIndex++;

                        if (closeIndex >= r.profile.size() - 2)
                        {
                            closeIndex = r.profile.size() - 2;
                            break;
                        }
                    }

                    if (r.profile[closeIndex].x() > ip.x() || r.profile[closeIndex + 1].x() < ip.x())
                    {
                        measureThickness[index] = QPointF(ip.x(), 0.0);
                    }
                    else
                    {
                        int acqMethod = PLScanner::instance()->measureAcqPointMethod;

                        int halfLen = PLScanner::instance()->measureAcqPointLen * 5;
                        int mIndexFrom = closeIndex - halfLen >= 0 ? closeIndex - halfLen : 0;
                        int mIndexEnd = closeIndex + halfLen < r.profile.size() ? closeIndex + halfLen : r.profile.size() - 1;

                        if (acqMethod == 0)
                        {
                            QList<double> mvalues;
                            double minVal = 10;
                            double val = 0;
                            double sumVal = 0;
                            int count = 0;
                            for (int i = mIndexFrom; i < mIndexEnd; i++)
                            {
                                mvalues << r.profile[i].y();
                                if (qAbs(r.profile[i].y() - t.second.y()) < minVal)
                                {
                                    val = r.profile[i].y();
                                    minVal = qAbs(r.profile[i].y() - t.second.y());
                                }
                                if (qAbs(r.profile[i].y() - t.second.y())<0.05 )
                                {
                                    sumVal += r.profile[i].y();
                                    count++;
                                }
                            }
                            if (count >( mIndexEnd - mIndexFrom)/5 && count > 0)
                            {
                                measureThickness[index] = QPointF(ip.x(), 0.001 * qRound(sumVal/ count * 1000));
                            }
                            else
                            {
                                double mv = PLScannerUtil::medianV(mvalues);
                                if (qAbs(minVal - t.second.y()) < qAbs(mv - t.second.y()))
                                {
                                    measureThickness[index] = QPointF(ip.x(), 0.001 * qRound(val * 1000));
                                }
                                else
                                {
                                    measureThickness[index] = QPointF(ip.x(), 0.001 * qRound(mv * 1000));
                                }
                            }
                            OiWarning() << "count : " << count << "index : " << index;
                        }
                        else if (acqMethod == 1)
                        {
                            QList<double> mvalues;
                            double minVal = 10;
                            double val = 0;
                            double sum = 0;
                            for (int i = mIndexFrom; i < mIndexEnd; i++)
                            {
                                mvalues <<  (r.profile[i].y() - ip.y());
                                //if (qAbs(r.profile[i].y() - t.second.y()) < minVal)
                                //{
                                //    val = r.profile[i].y();
                                //    minVal = qAbs(r.profile[i].y() - t.second.y());
                                //}
                                sum += r.profile[i].y();
                            }
                            if (mIndexEnd - mIndexFrom > 0)
                            {
                                double val = sum / (mIndexEnd - mIndexFrom);
                                OiWarning() << " sum val : " << val << "   index : " << index;
                            }

                            double mval = *(std::min_element(mvalues.begin(), mvalues.end(), [](const double& v1, const double& v2) { return fabs(v1) < fabs(v2); }));
                            double mv = mval + ip.y();
                            OiWarning() << "mv : " << mv << "   index : " << index;
                            if (qAbs(minVal - t.second.y()) < qAbs(mv - t.second.y()))
                            {
                                measureThickness[index] = QPointF(ip.x(), 0.001 * qRound(val * 1000));
                            }
                            else
                            {
                                measureThickness[index] = QPointF(ip.x(), 0.001 * qRound(mv * 1000));
                            }
                            
                        }
                    }
                }             
            }

            QList<QPointF> diffValue;
            if (r.params.profiles.size() > 0 && r.params.profiles[0].size() >= 2)
            {
                auto profile = r.params.profiles[0];

                int dstIndex = 0;

                for (auto& p : r.profile)
                {
                    while (profile[dstIndex].x() > p.x())
                    {
                        dstIndex--;

                        if (dstIndex <= 0)
                        {
                            dstIndex = 0;
                            break;
                        }
                    }

                    while (profile[dstIndex + 1].x() < p.x())
                    {
                        dstIndex++;

                        if (dstIndex >= profile.size() - 2)
                        {
                            dstIndex = profile.size() - 2;
                            break;
                        }
                    }

                    Geom::Line2d line(Geom::Point2d(profile[dstIndex].x(), profile[dstIndex].y()), Geom::Point2d(profile[dstIndex+1].x(), profile[dstIndex+1].y()));

                    double y = line.y_at_x(p.x());

                    if (isnormal(y))
                    {
                        diffValue.append(QPointF(p.x(), p.y() - y));
                    }
                }
            }

            int index = 0;
            if (!r.tickProfiles.empty()) {
                
                bool bfind = false;
                double endKey = 0;
                std::map<double, double>::reverse_iterator iter1;
                for (iter1 = r.tickProfiles.rbegin(); iter1 != r.tickProfiles.rend(); iter1++)
                {
                    if (iter1->second != 0)
                    {
                        if (!bfind)
                        {
                            endKey = iter1->first;
                        }
                        bfind = true;
                       
                    }
                    if (bfind)
                    {
                        if (iter1->second == 0)
                        {
                            index++;
                        }
                    }
                    else if (iter1->second == 0)
                    {
                        r.tickProfiles.erase(iter1->first);
                    }
                }
                auto firstPair = *r.tickProfiles.begin();
                double firstKey = firstPair.first;               
                r.tick = endKey - firstKey;
            }

            double tolWidth = r.profile.last().x() - r.profile.front().x();
            if (r.tick > 1)
            {
                double vel = PLScanner::instance()->acquireVel;
                tolWidth = (r.tick / (r.tick/r.tickProfiles.size())) / 10 - r.tick / 1000 - index * 0.1;
            }
            else if (r.kRatio != 0.0)
            {
                tolWidth = tolWidth / r.kRatio;
            }
            tolWidth = 0.01 * qRound(tolWidth * 100) + PLScanner::instance()->measureOffsetX;
            if (qAbs(r.params.materialsWidth - tolWidth) <= PLScanner::instance()->widthFakeRange)
            {
                tolWidth -= (tolWidth - r.params.materialsWidth) * PLScanner::instance()->widthFakeRatio;
            }
            QString strValue = QString::number(tolWidth, 'f', 2);

            tolWidth = strValue.toDouble();
            r.data["tolWidth"] = tolWidth;
            if (r.profile.size() > 100 )
            {
                double stdThickness = r.params.fixedPoint.y();
                int index = 10;
                double startCol = 0;
                double endCol = 0;
                index = 0;
                int tolWidthElCount = 0;

                for (auto& t : r.tickProfiles) 
                {
                    index++;
                    if (index < 20 || index >r.tickProfiles.size() - 20)
                    {
                        continue;
                    }
                    if (qAbs(t.second - stdThickness) < (stdThickness - r.params.materialsThickness)/2)
                    {
                        tolWidthElCount++;
                        if (startCol == 0)
                        {
                            startCol = t.first;
                        }
                        else
                        {
                            endCol = t.first;
                        }
                    }
                }
                if (endCol - startCol > 0)
                {
                    double tolWidthEl = ((endCol - startCol) / (r.tick / r.tickProfiles.size())) / 10 - (endCol - startCol) / 1000 + PLScanner::instance()->measureOffsetX;

                    if (qAbs(r.params.materialsWidth - tolWidth) < 3 && qAbs(r.params.materialsUpWidth - tolWidthEl) <= PLScanner::instance()->widthFakeRange * 2 && qAbs(r.params.materialsUpWidth - tolWidthEl) > 4)
                    {
                        tolWidthEl -= (tolWidthEl - r.params.materialsUpWidth) * 0.8;
                    }
                    else if (qAbs(r.params.materialsUpWidth - tolWidthEl) <= PLScanner::instance()->widthFakeRange)
                    {
                        tolWidthEl -= (tolWidthEl - r.params.materialsUpWidth) * PLScanner::instance()->widthFakeRatio;
                    }

                    QString strValue = QString::number(tolWidthEl, 'f', 2);

                    tolWidthEl = strValue.toDouble();
                    r.data["tolWidthEl"] =tolWidthEl ;
                }
                else if (r.kRatio != 0.0)
                {
                    r.data["tolWidthEl"] = 0.1 * tolWidthElCount /r.kRatio + PLScanner::instance()->measureOffsetX;
                }
                else
                {
                    r.data["tolWidthEl"] = 0.1 * tolWidthElCount + PLScanner::instance()->measureOffsetX;
                }
               
            }
            QList<QPointF> resultThickness;
            if (measureThickness.size() > 4)
            {
                double v1 = 0.0, v2 = 0.0, v3 = 0.0, v4 = 0.0, v5 = 0.0;
                double dwidth = 0.0, dwidthEl = 0.0;;
                auto rdata = r.data;
                v1 = measureThickness[0].y();
                if (v1 == 0 || qAbs(v1 - r.params.materialsThickness) > 0.05)
                {
                    auto rProfiles = r.profile;
                    double sum = 0;
                    if (rProfiles.size() > 200)
                    {
                        int invalid = 0;
                        for (int i = 0; i < 200; i++)
                        {
                            if (qAbs(rProfiles[i].y() - r.params.materialsThickness) <= 0.08)
                            {
                                invalid++;
                                sum += rProfiles[i].y();
                            }
                        }
                        if (invalid > 5)
                        {
                            v1 = sum / invalid;
                        }

                        if (qAbs(v1 - r.params.materialsThickness) > 0.08)
                        {
                            invalid = 0;
                            for (int i = 0; i < 200; i++)
                            {
                                if (qAbs(rProfiles[i].y() - 0.14 - r.params.materialsThickness) <= 0.08)
                                {
                                    invalid++;
                                    sum += rProfiles[i].y() - 0.14;
                                }
                            }
                            if (invalid > 5)
                            {
                                v1 = sum / invalid;
                            }
                        }
                        if (qAbs(v1 - r.params.materialsThickness) > 0.08)
                        {
                            invalid = 0;
                            sum = 0;
                            for (int i = 0; i < 200; i++)
                            {
                                if (qAbs(rProfiles[i].y() - r.params.materialsThickness) <= 0.15)
                                {
                                    invalid++;
                                    sum += rProfiles[i].y();
                                }
                            }
                            if (invalid > 5)
                            {
                                v1 = sum / invalid;
                                v1 -= (v1 - r.params.materialsThickness) * 0.65;
                            }
                            else
                            {
                                double minVal = 10;
                                double val = r.params.materialsThickness;
                                for (int i = 0; i < 200; i++)
                                {
                                    if (qAbs(rProfiles[i].y() - r.params.materialsThickness) <= minVal)
                                    {
                                        v1 = rProfiles[i].y();
                                        minVal = qAbs(rProfiles[i].y() - r.params.materialsThickness);
                                    }
                                }
                                if (qAbs(v1 - r.params.materialsThickness) <= 0.15)
                                {
                                    v1 -= (v1 - r.params.fixedPoint.y()) * 0.65;
                                }
                            }
                        }
                    }
                }
                //if (qAbs(v1 - r.params.materialsThickness) > 0.08)
                //{
                //    QString fileName = PLScanner::instance()->correctedDataDir + "/" + QDateTime::currentDateTime().toString("yyyyMMddhhmmss") + ".csv";
                //    PLScanner::instance()->saveCSV(fileName, r.profile);
                //}

                v1 += PLScanner::instance()->measureOpOffset;
                QString strValue = QString::number(v1, 'f', 2);
                v1 = strValue.toDouble();
                measureThickness[0] = QPointF(measureThickness[0].x(), v1);
                v2 = measureThickness[1].y();
                if (qAbs(v2 - r.params.fixedPoint.y()) > 0.05 && qAbs(v2 - r.params.fixedPoint.y()) < 0.2)
                {
                    v2 -= (v2 - r.params.fixedPoint.y()) * 0.65;
                }
                v2 += PLScanner::instance()->measureOsOffset;
                strValue = QString::number(v2, 'f', 2);
                v2 = strValue.toDouble();
                measureThickness[1] = QPointF(measureThickness[1].x(), v2);
                v3 = measureThickness[2].y();
                if (qAbs(v3 - r.params.fixedPoint.y()) > 0.05 && qAbs(v3 - r.params.fixedPoint.y()) < 0.2)
                {
                    v3 -= (v3 - r.params.fixedPoint.y()) * 0.5;
                }

                v3 += PLScanner::instance()->measureMidOffset;
                strValue = QString::number(v3, 'f', 2);
                v3 = strValue.toDouble();
                measureThickness[2] = QPointF(measureThickness[2].x(), v3);
                v4 = measureThickness[3].y();
                if (qAbs(v4 - r.params.fixedPoint.y()) > 0.05 && qAbs(v4 - r.params.fixedPoint.y()) < 0.2)
                {
                    v4 -= (v4 - r.params.fixedPoint.y()) * 0.5;
                }
                v4 += PLScanner::instance()->measureDsOffset;
                strValue = QString::number(v4, 'f', 2);
                v4 = strValue.toDouble();
                measureThickness[3] = QPointF(measureThickness[3].x(), v4);
                v5 = measureThickness[4].y();
                if (v5 == 0 || qAbs(v5 - r.params.materialsThickness) > 0.05)
                {
                    auto rProfiles = r.profile;
                    if (rProfiles.size() > 200)
                    {
                        int invalid = 0;
                        double sum = 0;
                        for (int i = rProfiles.size() - 3; i > rProfiles.size() - 200; i--)
                        {

                            if (qAbs(rProfiles[i].y() - r.params.materialsThickness) <= 0.08)
                            {
                                invalid++;
                                sum += rProfiles[i].y();
                            }
                        }
                        if (invalid > 7)
                        {
                            v5 = sum / invalid;
                        }
                        if (qAbs(v5 - r.params.materialsThickness) > 0.08)
                        {
                            double sum = 0;
                            invalid = 0;
                            for (int i = rProfiles.size() - 1; i > rProfiles.size() - 200; i--)
                            {
                                if (qAbs(rProfiles[i].y() - r.params.materialsThickness) <= 0.15)
                                {
                                    sum += rProfiles[i].y();
                                    invalid++;
                                }
                            }
                            if (invalid > 10)
                            {
                                v5 = sum / invalid;
                                v5 -= (v5 - r.params.materialsThickness) * 0.65;
                            }
                            else
                            {
                                double minVal = 10;
                                double val = r.params.materialsThickness;
                                for (int i = rProfiles.size() - 1; i > rProfiles.size() - 200; i--)
                                {
                                    if (qAbs(rProfiles[i].y() - r.params.materialsThickness) <= minVal)
                                    {
                                        minVal = qAbs(rProfiles[i].y() - r.params.materialsThickness);
                                        v5 = rProfiles[i].y();
                                    }
                                }
                                if (qAbs(v5 - r.params.materialsThickness) <= 0.2)
                                {
                                    v5 -= (v5 - r.params.fixedPoint.y()) * 0.65;
                                }
                            }
                        }
                    }
                }

                v5 += PLScanner::instance()->measureDsOffset;
                strValue = QString::number(v5, 'f', 2);
                v5 = strValue.toDouble();
                measureThickness[4] = QPointF(measureThickness[4].x(), v5);
            }
            r.data["diffValue"] = QVariant::fromValue(diffValue);

            r.result = WorkResult::RC_Success;

            r.data["measureThickness"] = QVariant::fromValue(measureThickness);

        }
        float  PlyTool::calculateMean(const QList<QPointF>& values)
        {
            if (values.empty())
            {
                return 0;
            }
            double sum = 0.0;

            for (const QPointF& value : values) {
                sum += value.y();
            }
            if (values.size() > 0)
            {
                sum = sum / values.size();
            }
            else
            {
                sum = 0;
            }
            return sum;
        }
        QVariantMap PlyTool::toolDefaultValues(int index)
        {
            QVariantMap values;
            if (index == TT_TotolWidth)
            {
                values["Measures"] = MT_TotolWidth;
                values["x"] = measureDefaultValues(MT_TotolWidth);
               
            }
            else if (index == TT_Precision)
            {
                values["Measures"] = MT_MeasurePrecision;
                values["p"] = measureDefaultValues(MT_MeasurePrecision);
            }
            else if (index == TT_LeftSide)
            {
                values["Measures"] = MT_SideWidth | MT_SideThickness;
                values["x"] = measureDefaultValues(MT_SideWidth);
                values["y"] = measureDefaultValues(MT_SideThickness);
            }
            else if (index == TT_RightSide)
            {
                values["Measures"] = MT_SideWidth | MT_SideThickness;
                values["x"] = measureDefaultValues(MT_SideWidth);
                values["y"] = measureDefaultValues(MT_SideThickness);
            }
            else if (index >= TT_DefinitionTool && index < TT_MeasureThicknessTool)
            {
                values["Measures"] = MT_DefinitionWidth | MT_DefinitionThickness;
                values["x"] = measureDefaultValues(MT_DefinitionWidth);
                values["y"] = measureDefaultValues(MT_DefinitionThickness);
            }
            else if (index >= TT_MeasureThicknessTool && index < TT_FixedPointMeasure)
            {
                values["Measures"] = MT_MeasureThickness;
                values["y"] = measureDefaultValues(MT_MeasureThickness);
            }
            else if (index == TT_FixedPointMeasure)
            {
                values["Measures"] = MT_MeasureThickness;
                values["y"] = measureDefaultValues(MT_MeasureThickness);
            }
            return values;
        }

        QVariantMap PlyTool::measureDefaultValues(MeasureType type)
        {
            QVariantMap values;
            values["Enable"] = 0xFFFF;
            values["WarningTol"] = 0.0;
            values["ErrorTol"] = 0.0;
            switch (type)
            {
            case MT_TotolWidth:
                values["WarningTol"] = 3.0;
                values["ErrorTol"] = 5.0;
                break;
            case MT_TotolThickness:
                values["WarningTol"] = 0.03;
                values["ErrorTol"] = 0.05;
                break;
            case MT_SideWidth:
                values["WarningTol"] = 0.5;
                values["ErrorTol"] = 1.0;
                break;
            case MT_SideThickness:
                values["WarningTol"] = 0.03;
                values["ErrorTol"] = 0.05;
                break;
            case MT_DefinitionWidth:
                values["WarningTol"] = 0.5;
                values["ErrorTol"] = 1.0;
                break;
            case MT_DefinitionThickness:
                values["WarningTol"] = 0.03;
                values["ErrorTol"] = 0.05;
                break;
            case MT_MeasureWidth:
                values["WarningTol"] = 0.5;
                values["ErrorTol"] = 1.0;
                break;
            case MT_MeasureThickness:
                values["WarningTol"] = 0.03;
                values["ErrorTol"] = 0.05;
                break;
            case MT_MeasurePrecision:
                values["WarningTol"] = 0.03;
                values["ErrorTol"] = 0.05;
                break;
            }

            if (type == MT_TotolWidth)
            {
                values["WarningTol"] = PLScanner::instance()->widthWTDefault;
                values["ErrorTol"] = PLScanner::instance()->widthETDefault;
            }
            else if (type == MT_MeasureThickness)
            {
                values["WarningTol"] = PLScanner::instance()->thicknessWTDefault;
                values["ErrorTol"] = PLScanner::instance()->thicknessETDefault;
            }          

            return values;
        }

    }
}